import 'dart:io';

import 'package:common_utils/common_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart' as l;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

import '../config/config.dart';
import '../utils/logger/file_output.dart';
import '../utils/logger/full_console_output.dart';
import '../utils/logger/none_output.dart';

class LogService extends GetxService {
  late l.Logger _logger;
  String? _logFilePath;

  String? get logFilePath => _logFilePath;


  Future<LogService> init() async {
    print("++++");
    _logger = await l.Logger(
      filter: l.ProductionFilter(),
      printer: l.SimplePrinter(printTime: true),
      output: await _getLogOutput(),
    );
    _logger.d('starting services ...');
    _logger.d("平台 ${GetPlatform.isAndroid ? 'Android' : 'iOS'}");
    final packageInfo = await PackageInfo.fromPlatform();
    _logger.d(
        'appName ${packageInfo.appName}, packageName: ${packageInfo.packageName}, version: ${packageInfo.version}, buildNumber: ${packageInfo.buildNumber}, buildSignature: ${packageInfo.buildSignature}');
    Get.log = (String value, {bool isError = false}) {
      _logger.d(value);
    };

    return this;
  }

  static l.Logger get logger => to._logger;

  static LogService get to => Get.find();

  Future<l.LogOutput> _getLogOutput() async {
    if (Env.isLogEnable) {
      FileOutput? fileLogger;
      FullConsoleOutput? consoleLogger;
      if (Env.isFileLogEnable) {
        _logFilePath = await _getLogFilePath();
        debugPrint('log file path $_logFilePath');
        File logFile = File(_logFilePath!);
        if (!logFile.existsSync()) {
          await logFile.create(recursive: true);
        }
        fileLogger = FileOutput(file: logFile);
      }
      if (Env.isConsoleLogEnable && kDebugMode) {
        consoleLogger = FullConsoleOutput();
      }
      if (fileLogger != null || consoleLogger != null) {
        if (fileLogger != null && consoleLogger != null) {
          return l.MultiOutput([consoleLogger, fileLogger]);
        }
        if (fileLogger != null) {
          return fileLogger;
        }
        if (consoleLogger != null) {
          return consoleLogger;
        }
      }
    }
    return NoneOutput();
  }

  Future<String> _getLogFilePath() async {
    final logFileName = '${DateUtil.formatDate(DateTime.now(), format: DateFormats.y_mo_d)}-log.txt';
    if (GetPlatform.isAndroid) {
      var cacheDir = await getExternalCacheDirectories();
      if (cacheDir != null && cacheDir.isNotEmpty) {
        return p.join(cacheDir.first.path, 'toy-car-log', logFileName);
      } else {
        var cacheDir = await getTemporaryDirectory();
        return p.join(cacheDir.path, 'toy-car-log', logFileName);
      }
    } else {
      var cacheDir = await getApplicationSupportDirectory();
      return p.join(cacheDir.path, 'toy-car-log', logFileName);
    }
  }

  Future<String> getLogFilePath({DateTime? dateTime}) async {
    final logFileName = '${DateUtil.formatDate(dateTime ?? DateTime.now(), format: DateFormats.y_mo_d)}-log.txt';
    if (GetPlatform.isAndroid) {
      var cacheDir = await getExternalCacheDirectories();
      if (cacheDir != null && cacheDir.isNotEmpty) {
        return p.join(cacheDir.first.path, 'toy-car-log', logFileName);
      } else {
        var cacheDir = await getTemporaryDirectory();
        return p.join(cacheDir.path, 'toy-car-log', logFileName);
      }
    } else {
      var cacheDir = await getApplicationSupportDirectory();
      return p.join(cacheDir.path, 'toy-car-log', logFileName);
    }
  }

  void e(dynamic message, {dynamic error, StackTrace? stackTrace}) {
    if (message is String) {
      _logger.e(message, error: error, stackTrace: stackTrace);
    } else if (message is Error) {
      message.toString();
      _logger.e('Error: $message', error: message, stackTrace: stackTrace ?? message.stackTrace);
    } else if (message is Exception) {
      _logger.e('Exception: $message', error: message, stackTrace: stackTrace);
    } else {
      _logger.e(message, error: error, stackTrace: stackTrace);
    }
  }
}
